package cn.cdutetc.library.service.impl;

import cn.cdutetc.library.entity.pojo.User;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.RandomUtil;
import cn.cdutetc.library.entity.dto.UserCreateDTO;
import cn.cdutetc.library.entity.dto.UserLoginDTO;
import cn.cdutetc.library.entity.dto.UserUpdateDTO;
import cn.cdutetc.library.entity.dto.UserVO;
import cn.cdutetc.library.entity.dto.UserExportDTO;
import cn.cdutetc.library.entity.dto.LoginResponseDTO;
import cn.cdutetc.library.entity.dto.MenuDTO;
import cn.cdutetc.library.service.MenuService;
import cn.cdutetc.library.util.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import cn.cdutetc.library.entity.dto.UserImportDTO;
import cn.cdutetc.library.entity.dto.UserImportTemplateDTO;
import cn.cdutetc.library.entity.enums.UserRoleEnum;
import cn.cdutetc.library.entity.enums.UserStatusEnum;
import cn.cdutetc.library.common.exception.BizException;
import cn.cdutetc.library.common.ExcelUtils;
import cn.cdutetc.library.common.UserExcelAnalysisEventListener;
import cn.cdutetc.library.mapper.UserMapper;
import cn.cdutetc.library.service.UserService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 用户服务实现类
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private MenuService menuService;
    
    @Autowired
    private JwtUtil jwtUtil;

    @Override
    public LoginResponseDTO login(UserLoginDTO loginDTO) {
        // 查询用户
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUsername, loginDTO.getUsername());
        User user = this.getOne(queryWrapper);
        
        // 用户不存在
        if (user == null) {
            throw new BizException("用户名或密码错误");
        }
        
        // 校验密码（明文对比，按数据库存储要求）
        if (!loginDTO.getPassword().equals(user.getPassword())) {
            throw new BizException("用户名或密码错误");
        }
        
        // 校验状态：仅当 inactive 禁止登录
        if (UserStatusEnum.INACTIVE.getCode().equals(user.getStatus())) {
            throw new BizException("账号已被停用，请联系管理员");
        }
        
        // 生成JWT Token
        String token = jwtUtil.generateToken(user.getUserId(), user.getUsername(), user.getRole());
        
        // 获取用户权限菜单
        List<MenuDTO> menuList = menuService.getMenusByRole(user.getRole());
        
        // 获取用户权限列表
        List<String> permissions = menuService.getPermissionsByRole(user.getRole());
        
        // 转换为VO
        UserVO userVO = convertToVO(user);
        
        // 构建登录响应
        return new LoginResponseDTO(token, userVO, menuList, permissions);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer createUser(UserCreateDTO createDTO) {
        // 检查用户名是否存在
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUsername, createDTO.getUsername());
        if (this.count(queryWrapper) > 0) {
            throw new BizException("用户名已存在");
        }
        
        // 校验角色
        UserRoleEnum role = UserRoleEnum.getByCode(createDTO.getRole());
        if (role == null) {
            throw new BizException("无效的角色类型");
        }
        
        // 创建用户
        User user = new User();
        BeanUtil.copyProperties(createDTO, user);
        
        // 明文存储密码（根据业务要求）
        user.setPassword(createDTO.getPassword());
        user.setCreateTime(LocalDateTime.now());
        user.setStatus(UserStatusEnum.ACTIVE.getCode());
        
        // 保存用户
        this.save(user);
        return user.getUserId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateUser(UserUpdateDTO updateDTO) {
        // 添加调试日志
        System.out.println("开始更新用户，DTO: " + updateDTO);
        System.out.println("查询用户ID: " + updateDTO.getUserId());
        
        // 检查用户是否存在
        User user = this.getById(updateDTO.getUserId());
        System.out.println("查询到的用户: " + user);
        
        if (user == null) {
            System.err.println("用户不存在，用户ID: " + updateDTO.getUserId());
            throw new BizException("用户不存在");
        }
        
        // 如果修改了用户名，检查是否重复
        if (StringUtils.isNotBlank(updateDTO.getUsername()) && !updateDTO.getUsername().equals(user.getUsername())) {
            LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(User::getUsername, updateDTO.getUsername());
            if (this.count(queryWrapper) > 0) {
                throw new BizException("用户名已存在");
            }
        }
        
        // 如果修改了角色，校验角色
        if (StringUtils.isNotBlank(updateDTO.getRole())) {
            UserRoleEnum role = UserRoleEnum.getByCode(updateDTO.getRole());
            if (role == null) {
                throw new BizException("无效的角色类型");
            }
        }
        
        // 如果修改了状态，校验状态
        if (StringUtils.isNotBlank(updateDTO.getStatus())) {
            UserStatusEnum status = UserStatusEnum.getByCode(updateDTO.getStatus());
            if (status == null) {
                throw new BizException("无效的状态类型");
            }
        }
        
        // 更新用户
        BeanUtil.copyProperties(updateDTO, user);
        return this.updateById(user);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteUser(Integer userId) {
        // 检查用户是否存在
        User user = this.getById(userId);
        if (user == null) {
            throw new BizException("用户不存在");
        }
        
        // 删除用户
        return this.removeById(userId);
    }

    @Override
    public UserVO getUserById(Integer userId) {
        // 查询用户
        User user = this.getById(userId);
        if (user == null) {
            throw new BizException("用户不存在");
        }
        
        // 转换为VO
        return convertToVO(user);
    }

    @Override
    public IPage<UserVO> pageUsers(Integer page, Integer size, String keyword, String role, String status) {
        // 构建查询条件
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        
        // 关键字搜索
        if (StringUtils.isNotBlank(keyword)) {
            queryWrapper.and(wrapper -> wrapper
                    .like(User::getUsername, keyword)
                    .or().like(User::getRealName, keyword)
                    .or().like(User::getPhone, keyword)
                    .or().like(User::getEmail, keyword));
        }
        
        // 角色筛选
        if (StringUtils.isNotBlank(role)) {
            queryWrapper.eq(User::getRole, role);
        }
        
        // 状态筛选
        if (StringUtils.isNotBlank(status)) {
            queryWrapper.eq(User::getStatus, status);
        }
        
        // 按创建时间倒序
        queryWrapper.orderByDesc(User::getCreateTime);
        
        // 分页查询
        Page<User> userPage = new Page<>(page, size);
        Page<User> resultPage = this.page(userPage, queryWrapper);
        
        // 转换为VO
        List<UserVO> userVOList = resultPage.getRecords().stream()
                .map(this::convertToVO)
                .collect(Collectors.toList());
        
        // 构建返回结果
        Page<UserVO> voPage = new Page<>(resultPage.getCurrent(), resultPage.getSize(), resultPage.getTotal());
        voPage.setRecords(userVOList);
        
        return voPage;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean changePassword(Integer userId, String oldPassword, String newPassword) {
        // 查询用户
        User user = this.getById(userId);
        if (user == null) {
            throw new BizException("用户不存在");
        }
        
        // 校验旧密码（明文对比）
        if (!oldPassword.equals(user.getPassword())) {
            throw new BizException("原密码错误");
        }
        
        // 更新密码（明文存储）
        user.setPassword(newPassword);
        return this.updateById(user);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String resetPassword(Integer userId) {
        // 查询用户
        User user = this.getById(userId);
        if (user == null) {
            throw new BizException("用户不存在");
        }
        
        // 生成随机密码
        String newPassword = RandomUtil.randomString(8);
        
        // 更新密码（明文存储）
        user.setPassword(newPassword);
        this.updateById(user);
        
        return newPassword;
    }
    
    @Override
    public void exportUsers(HttpServletResponse response, String keyword) {
        // 查询用户数据
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        if (StringUtils.isNotBlank(keyword)) {
            queryWrapper.like(User::getUsername, keyword)
                    .or().like(User::getRealName, keyword)
                    .or().like(User::getPhone, keyword)
                    .or().like(User::getEmail, keyword);
        }
        queryWrapper.orderByDesc(User::getCreateTime);
        
        List<User> users = this.list(queryWrapper);
        
        // 转换为导出DTO
        List<UserExportDTO> exportList = users.stream()
                .map(this::convertToExportDTO)
                .collect(Collectors.toList());
        
        // 导出Excel
        String fileName = "用户数据_" + System.currentTimeMillis();
        ExcelUtils.responseExcelFile(exportList, response, fileName, UserExportDTO.class);
    }
    
    @Override
    public void downloadImportTemplate(HttpServletResponse response) {
        // 创建模板数据
        List<UserImportTemplateDTO> templateList = new ArrayList<>();
        UserImportTemplateDTO template = new UserImportTemplateDTO();
        template.setUsername("示例用户名");
        template.setPassword("示例密码");
        template.setRealName("示例姓名");
        template.setRole("normal_user");
        template.setPhone("13800138000");
        template.setEmail("example@email.com");
        template.setStatus("active");
        templateList.add(template);
        
        // 导出模板
        String fileName = "用户导入模板_" + System.currentTimeMillis();
        ExcelUtils.responseExcelFile(templateList, response, fileName, UserImportTemplateDTO.class);
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String importUsers(MultipartFile file) {
        if (file == null || file.isEmpty()) {
            throw new BizException("请选择要导入的文件");
        }
        
        // 检查文件格式
        String fileName = file.getOriginalFilename();
        if (fileName == null || (!fileName.endsWith(".xlsx") && !fileName.endsWith(".xls"))) {
            throw new BizException("请上传Excel格式文件(.xlsx或.xls)");
        }
        
        try {
            // 创建监听器
            UserExcelAnalysisEventListener listener = new UserExcelAnalysisEventListener();
            
            // 读取Excel文件
            List<UserImportDTO> importList = ExcelUtils.readExcelFile(
                    file.getInputStream(), 
                    UserImportDTO.class, 
                    listener
            );
            
            // 检查是否有数据校验错误
            if (listener.hasErrors()) {
                String errorMsg = String.join("; ", listener.getErrorMessages());
                throw new BizException("数据校验失败：" + errorMsg);
            }
            
            if (importList.isEmpty()) {
                throw new BizException("Excel文件中没有有效数据");
            }
            
            // 批量导入用户
            int successCount = 0;
            int failCount = 0;
            StringBuilder errorMessages = new StringBuilder();
            
            for (int i = 0; i < importList.size(); i++) {
                UserImportDTO importDTO = importList.get(i);
                try {
                    // 检查用户名是否已存在
                    LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
                    queryWrapper.eq(User::getUsername, importDTO.getUsername());
                    if (this.count(queryWrapper) > 0) {
                        failCount++;
                        errorMessages.append("第").append(i + 2).append("行：用户名'").append(importDTO.getUsername()).append("'已存在；");
                        continue;
                    }
                    
                    // 创建用户
                    User user = new User();
                    user.setUsername(importDTO.getUsername());
                    user.setPassword(importDTO.getPassword());
                    user.setRealName(importDTO.getRealName());
                    user.setRole(importDTO.getRole());
                    user.setPhone(importDTO.getPhone());
                    user.setEmail(importDTO.getEmail());
                    user.setStatus(StringUtils.isNotBlank(importDTO.getStatus()) ? importDTO.getStatus() : UserStatusEnum.ACTIVE.getCode());
                    user.setCreateTime(LocalDateTime.now());
                    
                    this.save(user);
                    successCount++;
                } catch (Exception e) {
                    failCount++;
                    errorMessages.append("第").append(i + 2).append("行：").append(e.getMessage()).append("；");
                }
            }
            
            String result = String.format("导入完成！成功：%d条，失败：%d条", successCount, failCount);
            if (failCount > 0) {
                result += "。失败原因：" + errorMessages.toString();
            }
            
            return result;
        } catch (IOException e) {
            throw new BizException("读取Excel文件失败：" + e.getMessage());
        }
    }
    
    @Override
    public IPage<UserVO> pageReaders(Integer page, Integer size, String keyword) {
        // 构建查询条件 - 只查询读者角色
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getRole, UserRoleEnum.READER.getCode());
        
        if (StringUtils.isNotBlank(keyword)) {
            queryWrapper.and(wrapper -> wrapper
                    .like(User::getUsername, keyword)
                    .or().like(User::getRealName, keyword)
                    .or().like(User::getPhone, keyword)
                    .or().like(User::getEmail, keyword));
        }
        
        queryWrapper.orderByDesc(User::getCreateTime);
        
        // 分页查询
        Page<User> userPage = new Page<>(page, size);
        Page<User> resultPage = this.page(userPage, queryWrapper);
        
        // 转换为VO
        List<UserVO> userVOList = resultPage.getRecords().stream()
                .map(this::convertToVO)
                .collect(Collectors.toList());
        
        // 构建返回结果
        Page<UserVO> voPage = new Page<>(resultPage.getCurrent(), resultPage.getSize(), resultPage.getTotal());
        voPage.setRecords(userVOList);
        
        return voPage;
    }
    
    @Override
    public List<UserVO> getAllReaders(String keyword) {
        // 构建查询条件 - 只查询读者角色
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getRole, UserRoleEnum.READER.getCode());
        queryWrapper.eq(User::getStatus, UserStatusEnum.ACTIVE.getCode());
        
        if (StringUtils.isNotBlank(keyword)) {
            queryWrapper.and(wrapper -> wrapper
                    .like(User::getUsername, keyword)
                    .or().like(User::getRealName, keyword)
                    .or().like(User::getPhone, keyword)
                    .or().like(User::getEmail, keyword));
        }
        
        queryWrapper.orderByDesc(User::getCreateTime);
        
        List<User> users = this.list(queryWrapper);
        
        return users.stream()
                .map(this::convertToVO)
                .collect(Collectors.toList());
    }
    
    @Override
    public void exportReaders(HttpServletResponse response, String keyword) {
        // 查询读者数据（仅查询normal_user角色）
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getRole, UserRoleEnum.READER.getCode());
        queryWrapper.eq(User::getStatus, UserStatusEnum.ACTIVE.getCode());
        
        if (StringUtils.isNotBlank(keyword)) {
            queryWrapper.and(wrapper -> wrapper
                    .like(User::getUsername, keyword)
                    .or().like(User::getRealName, keyword)
                    .or().like(User::getPhone, keyword)
                    .or().like(User::getEmail, keyword));
        }
        queryWrapper.orderByDesc(User::getCreateTime);
        
        List<User> readers = this.list(queryWrapper);
        
        // 转换为导出DTO
        List<UserExportDTO> exportList = readers.stream()
                .map(this::convertToExportDTO)
                .collect(Collectors.toList());
        
        // 导出Excel
        String fileName = "读者数据_" + System.currentTimeMillis();
        ExcelUtils.responseExcelFile(exportList, response, fileName, UserExportDTO.class);
    }
    
    /**
     * 将User实体转换为UserVO
     * @param user 用户实体
     * @return 用户VO
     */
    private UserVO convertToVO(User user) {
        if (user == null) {
            return null;
        }
        UserVO userVO = new UserVO();
        BeanUtil.copyProperties(user, userVO);
        return userVO;
    }
    
    /**
     * 将User实体转换为UserExportDTO
     * @param user 用户实体
     * @return 用户导出DTO
     */
    private UserExportDTO convertToExportDTO(User user) {
        if (user == null) {
            return null;
        }
        UserExportDTO exportDTO = new UserExportDTO();
        BeanUtil.copyProperties(user, exportDTO);
        
        // 转换角色和状态为中文描述
        UserRoleEnum role = UserRoleEnum.getByCode(user.getRole());
        if (role != null) {
            exportDTO.setRoleDesc(role.getDesc());
        }
        
        UserStatusEnum status = UserStatusEnum.getByCode(user.getStatus());
        if (status != null) {
            exportDTO.setStatusDesc(status.getDesc());
        }
        
        return exportDTO;
    }
}